package drds.common.db.xml_mapping.mapping;


import drds.common.db.xml_mapping.executor.key_generator.AutoSetModePrimaryKeyGenerator;
import drds.common.db.xml_mapping.executor.key_generator.NoPrimaryKeyGenerator;
import drds.common.db.xml_mapping.executor.key_generator.PrimaryKeyGenerator;
import drds.common.db.xml_mapping.script.LanguageDriver;
import drds.common.db.xml_mapping.session.Configuration;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public final class Mapper {

  private String resource;
  private Configuration configuration;
  private String id;

  private StatementType statementType;

  private SqlSource sqlSource;

  private ParameterMap parameterMap;
  private List<ResultMap> resultMaps;


  private SqlType sqlType;
  private PrimaryKeyGenerator primaryKeyGenerator;
  private String[] keyProperties;
  private String[] keyColumns;


  private LanguageDriver lang;
  private String[] resultSets;

  Mapper() {
    // constructor disabled
  }

  private static String[] delimitedStringToArray(String in) {
    if (in == null || in.trim().length() == 0) {
      return null;
    } else {
      return in.split(",");
    }
  }

  public PrimaryKeyGenerator getPrimaryKeyGenerator() {
    return primaryKeyGenerator;
  }

  public SqlType getSqlType() {
    return sqlType;
  }

  public String getResource() {
    return resource;
  }

  public Configuration getConfiguration() {
    return configuration;
  }

  public String getId() {
    return id;
  }


  public StatementType getStatementType() {
    return statementType;
  }


  public ParameterMap getParameterMap() {
    return parameterMap;
  }

  public List<ResultMap> getResultMaps() {
    return resultMaps;
  }


  public String[] getKeyProperties() {
    return keyProperties;
  }

  public String[] getKeyColumns() {
    return keyColumns;
  }


  public LanguageDriver getLang() {
    return lang;
  }

  public String[] getResultSets() {
    return resultSets;
  }


  public BindSql getBoundSql(Object parameterObject) {
    BindSql bindSql = sqlSource.getBoundSql(parameterObject);
    List<ParameterMapping> parameterMappings = bindSql.getParameterMappingList();
    if (parameterMappings == null || parameterMappings.isEmpty()) {
      bindSql = new BindSql(configuration, bindSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
    }
    return bindSql;
  }

  public static class Builder {
    private Mapper mapper = new Mapper();

    public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlType sqlType) {
      mapper.configuration = configuration;
      mapper.id = id;
      mapper.sqlSource = sqlSource;
      mapper.statementType = StatementType.prepared_statement;

      mapper.parameterMap = new ParameterMap.Builder("defaultParameterMap", null, new ArrayList<>()).build();
      mapper.resultMaps = new ArrayList<>();
      mapper.sqlType = sqlType;
      mapper.primaryKeyGenerator = SqlType.insert.equals(sqlType) && configuration.isUseGeneratedKeys() ? AutoSetModePrimaryKeyGenerator.INSTANCE : NoPrimaryKeyGenerator.INSTANCE;


      mapper.lang = configuration.getDefaultScriptingLanguageInstance();
    }

    public Builder resource(String resource) {
      mapper.resource = resource;
      return this;
    }

    public String id() {
      return mapper.id;
    }

    public Builder parameterMap(ParameterMap parameterMap) {
      mapper.parameterMap = parameterMap;
      return this;
    }

    public Builder resultMaps(List<ResultMap> resultMaps) {
      mapper.resultMaps = resultMaps;

      return this;
    }


    public Builder statementType(StatementType statementType) {
      mapper.statementType = statementType;
      return this;
    }


    public Builder keyGenerator(PrimaryKeyGenerator primaryKeyGenerator) {
      mapper.primaryKeyGenerator = primaryKeyGenerator;
      return this;
    }

    public Builder keyProperty(String keyProperty) {
      mapper.keyProperties = delimitedStringToArray(keyProperty);
      return this;
    }

    public Builder keyColumn(String keyColumn) {
      mapper.keyColumns = delimitedStringToArray(keyColumn);
      return this;
    }

    public Builder lang(LanguageDriver driver) {
      mapper.lang = driver;
      return this;
    }

    public Builder resultSets(String resultSet) {
      mapper.resultSets = delimitedStringToArray(resultSet);
      return this;
    }

    /**
     * @deprecated Use {@link #resultSets}
     */
    @Deprecated
    public Builder resulSets(String resultSet) {
      mapper.resultSets = delimitedStringToArray(resultSet);
      return this;
    }

    public Mapper build() {
      assert mapper.configuration != null;
      assert mapper.id != null;
      assert mapper.sqlSource != null;
      assert mapper.lang != null;
      mapper.resultMaps = Collections.unmodifiableList(mapper.resultMaps);
      return mapper;
    }
  }

}
